import * as Http from 'http';
import * as Url from 'url';
import * as Querystring from 'querystring';

export interface Context<T> {
    request: Http.IncomingMessage,
    response: Http.ServerResponse,
    parameters: T,
    attributes: {[index: string]: any}
}

export interface Handle<T, R> {
    (ctx: Context<T>): Promise<R>;
}

export default class Application {
    private server: Http.Server;
    private handles: {[index: string]: Handle<any, any>};

    constructor(port?: number, hostname?: string) {
        if (!hostname)
            hostname = '127.0.0.1';
        this.handles = {};
        this.server = Http.createServer(
            (req: Http.IncomingMessage, res: Http.ServerResponse) => {
                this.route(req, res);
        });
        this.server.listen(port, hostname);
        console.log("Server running at http://%s:%d/", hostname, port);
    }

    use<T, R>(paths: string | string[], handle: Handle<T, R>): void {
        if (typeof paths === "string")
            this.use2(paths, handle);
        else
            for (let path of paths)
                this.use2(path, handle);
    }

    private use2<T, R>(path: string, handle: Handle<T, R>): void {
        this.handles[path] = handle;
        console.log('map handle = %s', path);
    }

    private async route(req: Http.IncomingMessage, res: Http.ServerResponse) {
        // 解析url中的参数
        const path = Url.parse(req.url || '/');
        console.log("地址访问: %s", path.pathname);
        let pathname: string = path.pathname || '/';
        if (path.query)
            console.log("URL 参数: %s", path.query);
        const method = this.handles[pathname] || this.handles['*'];
        if (method) {
            try {
                const arg = await this.parse(path, req, res);
                if (arg)
                    console.log('访问参数: ', arg);
                const result = await method({request: req, response: res,
                    parameters: arg, attributes: {}});
                const clsName = typeof result;
                res.statusCode = 200;
                if (clsName === "string") {
                    res.setHeader("Content-Type", "text/html;charset=utf-8");
                    res.end(result);
                } else if(clsName === "object" && result) {
                    res.setHeader("Content-Type", "application/json;charset=utf-8");
                    res.end(JSON.stringify(result));
                }
            } catch (e) {
                console.log('error: ', e);
                res.statusCode = 500;
                res.setHeader("Content-Type", "text/plain;charset=utf-8");
                res.end("Internal error of the system.\n");
            }
        }
        else {
            console.log('%s 是无效路径', path.pathname);
            res.statusCode = 404;
            res.setHeader("Content-Type", "text/plain;charset=utf-8");
            res.end("Page not found.\n");
        }
    }

    private async parse(path: Url.UrlWithStringQuery, req: Http.IncomingMessage,
            res: Http.ServerResponse) {
        return new Promise((resolve, reject) => {
            const query = path.query ? Querystring.parse(path.query) : null;
            let arg = {...query};
            // 处理post提交的数据
            let body = '';
            req.on('data', (thunk) => {
                body += thunk;
            });
            req.on('end', () => {
                console.log('POST内容: %s', body);
                // 解析post提交的json字符串
                try {
                    if (body)
                        arg = { ...arg, ...JSON.parse(body) };
                } catch (e) {
                    reject(e);
                }
                resolve(arg);
            });
            req.on('error', (e) => {
                reject(e);
            });
        });
    }
}
